package com.hotel.controller;

import com.alibaba.fastjson.JSONObject;
import com.hotel.component.BaseController;
import com.hotel.component.IocContainer;
import com.hotel.entity.Notify;
import com.hotel.entity.PageBean;
import com.hotel.entity.User;
import com.hotel.exception.EntityException;
import com.hotel.service.NotifyService;
import com.hotel.service.impl.NotifyServiceImpl;
import org.apache.catalina.core.ApplicationContext;
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileUpload;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.PageContext;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * @Author Str
 * @Date 2021/10/28 21:26
 * @Description :公告管理
 */
@WebServlet("/notify/*")
public class NotifyController extends BaseController {
    private NotifyService notifyService = (NotifyService) IocContainer.getBean("NotifyService");

    /*
     * 映射地址: /Notify/viewAddNotify
          内部转发: /WEB-INF/jsp/notify/addNotify.jsp
              (你要提前准备该文件)
    */
    public String viewAddNotify(HttpServletRequest req, HttpServletResponse resp)
            throws IOException, ServletException {
        return "forward:/jsp/notify/addNotify.jsp";
    }

    // 跳转到列表
    public String viewList(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        return "forward:/jsp/notify/list.jsp";
    }

    public String viewEditNotify(HttpServletRequest req, HttpServletResponse resp)
            throws IOException, ServletException {
        Notify notify = makeNotify(req);
        System.out.println("notify:"+notify);
        JSONObject jsObj = new JSONObject();
        String respTxt = "";
        try {
            notifyService.updateNotify(notify);
            jsObj.put("result", "success");
            respTxt = jsObj.toString();
        } catch (Exception e) {
            e.printStackTrace();
            respTxt = packErrMsg(e); //打包错误信息
        }
        return "data:" + respTxt;
    }

    // 将返回的数据封装成对象
    public Notify makeNotify(HttpServletRequest req) {
        Notify notify = new Notify();
        //{1}修改时使用。
        notify.setId(req.getParameter("id"));
        notify.setNotifyName(req.getParameter("notifyName"));
        notify.setUploader(req.getParameter("uploader"));
        notify.setFileName(req.getParameter("fileName"));
        notify.setNote(req.getParameter("note"));
        return notify;
    }

    // 删除公告
    public String delNotify(HttpServletRequest req, HttpServletResponse resp){
        JSONObject jo = new JSONObject();
        String id = req.getParameter("id");
        String respTxt = "";
        try {
            notifyService.deleteNotify(id);
            jo.put("result", "success");
            respTxt = jo.toString();
        } catch (SQLException | EntityException e) {
            e.printStackTrace();
            respTxt = packErrMsg(e); //打包错误信息
        }
        return "data:" + respTxt;
    }

    // 根据id获取公告
    public String getNotify(HttpServletRequest req, HttpServletResponse resp)
            throws IOException, ServletException {
        //{1}获取 id 的值
        String id = req.getParameter("id");
        Notify notify = null;
        JSONObject jsObj = new JSONObject();
        String respTxt = "";
        try {
            //{2}根据 id 获取用户
            notify = notifyService.getNotifyById(id);
            //{3}存入相关信息
            jsObj.put("result", "success");
            jsObj.put("notify", notify);
            respTxt = jsObj.toString();
        } catch (Exception e) {
            e.printStackTrace();
            respTxt = packErrMsg(e); //打包错误信息
        }
        return "data:" + respTxt;
    }

    /**
     * 映射地址: /Notify/jsonList
     * 提交参数: page, limit, ...
     *
     * @return java.lang.String
     */
    public String jsonList(HttpServletRequest req, HttpServletResponse resp) {
        //{1}获取前端提交的关键字 [调BaseController的方法]
        Map<String, Object> keyWords = getKeyWords(req);
        for (String s : keyWords.keySet()) {
            System.out.println("key::" + s + ",value::" + keyWords.get(s));
        }
        String respTxt = "";
        PageBean<Notify> page = null;
        try {
            //{2}调用 service 方法查询数据(传入关键字)
            page = notifyService.getNotifyList(keyWords);
            //{3}转成 json 格式数据.
            respTxt = page.toJSON();
        } catch (Exception e) {
            e.printStackTrace();  //包装错误信息..
            respTxt = packErrMsg(e);
        }
        //{4}返回数据到 LayUI 表格组件。
        return "data:" + respTxt;
    }

    // 新增公告
    //映射地址: /Notify/saveNotify
    public String saveNotify(HttpServletRequest req, HttpServletResponse resp)
            throws IOException, ServletException {
        //{1}获取到 请求上下文 对象
        ServletRequestContext reqCtx = new ServletRequestContext(req);
        //{2}判断上传数据的格式是否正确.
        boolean ret = FileUpload.isMultipartContent(reqCtx);
        if (!ret) {  //格式不对..
            //{3}这种情况不应该发生。【开发阶段】
            throw new IOException("上传格式错误。");
        }
        List<FileItem> list = null;
        //{4}获取会话对象
        HttpSession session = req.getSession();
        //{5}取出当前登录用户。
        User curUser = (User) session.getAttribute("user");
        //{6}设置跳转地址。
        String target = "/notify/viewAddNotify"; //{失败}
        //{7}传递的参数。
        String urlMsg = "";
        Notify notify = null;
        try {
            //{8}获取所有上传的数据项。
            list = getFileItems(reqCtx);
            //{9}放到以下方法中解析, 生成 notify..
            notify = parseNotify(list);
            //{10}设置上传者 id
            notify.setUploader(curUser.getId());
            //{11}调用 service 保存公告..
            notifyService.saveNotify(notify);
            //{12}设置成功跳转地址
            target = "/notify/viewList"; //成功地址
            //{13}打包消息 op, notifyName, result, cause
            String notifyName = notify.getNotifyName();
            urlMsg = packRespMsg("addNotify", notifyName,
                    "success", "none");
        } catch (Exception e) {
            e.printStackTrace();
            urlMsg = packRespMsg("addNotify", notify.getNotifyName(),
                    "failed", e.getMessage());
        }
        return "redirect:" + target + urlMsg;
    }

    private String packRespMsg(String op, String notifyName,
                               String result, String msg) {
        StringBuffer sb = new StringBuffer("?");
        try {
            msg = URLEncoder.encode(msg, "UTF-8");
            notifyName = URLEncoder.encode(
                    notifyName, "UTF-8");
            sb.append("op=" + op);
            sb.append("&notifyName=" + notifyName);
            sb.append("&result=" + result);
            sb.append("&cause=" + msg);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    private List<FileItem> getFileItems(ServletRequestContext reqCtx)
            throws FileUploadException {

        ServletContext c1;        //[接口]
        ApplicationContext c2;    //[实现类]


        //HttpSessionContext c3;
        ServletRequestContext c4;
        PageContext c5;

        //{1}创建磁盘工厂。
        DiskFileItemFactory factory = new DiskFileItemFactory();
        //{2}设置临时存放点。
        File temp = new File("D:\\Projects\\temp"); //先创建好这个目录
        factory.setRepository(temp);
        //{3}创建文件上传器。(传入磁盘工厂)
        ServletFileUpload upload = new ServletFileUpload(factory);
        //{4}设置请求数据编码格式。
        upload.setHeaderEncoding("UTF-8");
        //{5}设置文件上传的上限值。
        upload.setFileSizeMax(50 * 1024 * 1024);  //50MB
        //{6}解析请求数据生成 FileItem 列表。
        //   (传入请求上下文对象)
        return upload.parseRequest(reqCtx);
    }

    private Notify parseNotify(List<FileItem> list)
            throws Exception {
        //{1}获取 4 项数据填入 Notify
        Notify notify = new Notify();
        //{2}迭代每一项表单项目。
        for (FileItem fi : list) {
            //{3}要区分一下哪些是普通表单 or 上传文件
            if (fi.isFormField()) { //普通表单
                //{4}获取字段名
                String fldName = fi.getFieldName();
                //{5}获取字段值
                String val = fi.getString("UTF-8");
                //{6}设置到相应的属性上。
                if ("notifyName".equals(fldName)) {
                    notify.setNotifyName(val);
                } else if ("note".equals(fldName)) {
                    notify.setNote(val);
                }
            } else {   //这里就是上传的文件
                //{7}获取文件名称
                String fileName = fi.getName();
                //{8}获取文件大小 {long-->String}
                String size = String.valueOf(
                        fi.getSize());
                //{9}设置三项内容到 notify.
                notify.setFileName(fileName);
                notify.setFileSize(size);
                notify.setFileItem(fi);
            }
        }
        return notify;
    }


    public String downNotify(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String id = req.getParameter("id");
        Notify notify = null;
        String upDir = NotifyServiceImpl.UPDIR;
        String retPath = "";
        try {
            System.out.println("下载公告id：" + id);
            // 根据id获取公告对象
            notify = notifyService.getNotifyById(id);
            System.out.println("notify："+notify);
            String fileName = notify.getFileName();
            // 执行下载，把文件输送到前端
            // 调用BaseController的下载方法
            download(upDir, fileName, resp);
            // 更新下载数
            notifyService.growDownloadCnt(id);
        } catch (Exception e) {
            e.printStackTrace();
            // 出错处理
            String msg = URLEncoder.encode("服务器内部错误", "UTF-8");
            retPath = "/notify/viewList?op=download&result=failed&cause=" + msg;
            return "redirect:" + retPath;
        }
        return "no_action";
    }

    private String packErrMsg(Exception e) {
        JSONObject jsObj = new JSONObject();
        jsObj.put("code", -1);
        jsObj.put("cause", e.getMessage());
        jsObj.put("result", "failed");
        //{ps}如果还有其它后面再加...
        return jsObj.toString();
    }
}
